package edu.cicese.alz;

import edu.cicese.alz.reports.AccelerometerCount;
import edu.cicese.alz.reports.AccelerometerMeasure;
import edu.cicese.alz.reports.AccelerometerUtil;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.SymbolAxis;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.LookupPaintScale;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.chart.title.PaintScaleLegend;
import org.jfree.data.xy.DefaultXYZDataset;
import org.jfree.data.xy.XYZDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;

import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

public class AccelerometerChart extends ApplicationFrame {

	private int userID = 0;
	private double dataType1Min = 8.5, dataType1Max = 11;
	private long tsAllowedWindow = 40000, tsMovementWindow = 10000;
	private int periodMs = 60000;
	public long filename;
	private long beginDate, endDate;
	int[] epoch10Count = new int[5];
	int intensityType = 0;
	int lightIntensity = 0, moderateIntensity = 0, hardIntensity = 0;
	int cLight = 0, cModerate = 0, cHard = 0;
	long[] lastDays = new long[]{1322553600075l, 1322553600094l, 1322380800102l, 1322467200535l, 1322467201760l,
			1324972830570l, 1324627222032l, 1324627226105l, 1324368000066l, 1324368030644l,
			1328169613916l, 1328083200077l, 1328169600057l, 1328256000743l, 1328083200099l};

//	int epoch10ll, epoch10hl, epoch10lm, epoch10hm, epoch10h;


	public AccelerometerChart(int userID, String path) {
		super("Accelerometer Chart: " + userID);

		this.userID = userID;
		JPanel localJPanel = new ChartPanel(createChart(createDatasetFromFiles(path)));
		localJPanel.setPreferredSize(new Dimension(1500, 750));
		setContentPane(localJPanel);
	}

	public AccelerometerChart(int userID, String path, boolean intensityChart) {
		super("Accelerometer Chart: " + userID);

		this.userID = userID;
		JPanel localJPanel = new ChartPanel(createIntensityChart(createDatasetFromCountFiles(path)));
//		JPanel localJPanel = new ChartPanel(createIntensityChart(createDatasetFromFiles(path)));
		localJPanel.setPreferredSize(new Dimension(1500, 750));
		setContentPane(localJPanel);
	}

	public AccelerometerChart(ResultSet resultSet, int userID, long beginDate, long endDate) {
		super("Accelerometer Chart: " + userID);

		this.userID = userID;
		this.beginDate = beginDate;
		this.endDate = endDate;
		JPanel localJPanel = new ChartPanel(createChart(createDataset(resultSet)));
		localJPanel.setPreferredSize(new Dimension(1500, 750));
		setContentPane(localJPanel);
	}

	public AccelerometerChart(ResultSet resultSet, int userID, long beginDate, long endDate, boolean intensityChart) {
		super("Physical Activity Intensity Chart: " + userID);

		this.userID = userID;
		this.beginDate = beginDate;
		this.endDate = endDate;
		createDatasetFromCounts(resultSet);
//		JPanel localJPanel = new ChartPanel(createIntensityChart(createDatasetFromCounts(resultSet)));
//		localJPanel.setPreferredSize(new Dimension(1500, 750));
//		setContentPane(localJPanel);
	}


	private XYZDataset createDataset(ResultSet resultSet) {
		DefaultXYZDataset localDefaultXYZDataset = new DefaultXYZDataset();
		int periods = 1440;

		ArrayList<AccelerometerMeasure> magnitudes = new ArrayList<>();
		double magnitude;
		long timestamp;
		try {
			while (resultSet.next()) {
				magnitude = Math.sqrt(
						Math.pow(resultSet.getDouble(1), 2) +
								Math.pow(resultSet.getDouble(2), 2) +
								Math.pow(resultSet.getDouble(3), 2));
				timestamp = resultSet.getLong(4);
				magnitudes.add(new AccelerometerMeasure(magnitude, timestamp));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

		if (!magnitudes.isEmpty()) {
			long d1 = magnitudes.get(0).getTimestamp();
			long d2 = magnitudes.get(magnitudes.size() - 1).getTimestamp();
			int numberOfDays = TimeUtil.getDayDifference(d1, d2);
			int dataSize = periods * numberOfDays;

//			System.out.println(numberOfDays);

			double[] xValues = new double[dataSize];
			double[] yValues = new double[dataSize];
			double[] zValues = new double[dataSize];

			Calendar cal = TimeUtil.getDayTimestamp(d1);
			long tsAux = cal.getTimeInMillis();
			long tsBegin = tsAux;

			for (int day = 0; day < numberOfDays; day++) {
//				System.out.println(day);
				for (int period = 0; period < periods; period++) {
					System.out.println(day + " " + period);
					xValues[(day * periods + period)] = tsBegin;
					yValues[(day * periods + period)] = period;
					zValues[(day * periods + period)] = getValue(magnitudes, tsAux);

					tsAux += periodMs;
				}

				cal.add(Calendar.DAY_OF_MONTH, 1);
				tsBegin = tsAux = cal.getTimeInMillis();
			}

			localDefaultXYZDataset.addSeries("Series 1", new double[][]{xValues, yValues, zValues});
			saveToFile(new double[][]{xValues, yValues, zValues}, "D:\\_proyectoAlz\\analysis\\gps charts\\" + userID + "\\", d1 + ".alz5");
			this.filename = d1;
		} else {
			int numberOfDays = TimeUtil.getDayDifference(beginDate, endDate - 1);
			int dataSize = periods * numberOfDays;
			double[] xValues = new double[dataSize];
			double[] yValues = new double[dataSize];
			double[] zValues = new double[dataSize];

			Calendar cal = TimeUtil.getDayTimestamp(beginDate);
			long tsAux = cal.getTimeInMillis();
			long tsBegin = tsAux;

			for (int day = 0; day < numberOfDays; day++) {
				for (int period = 0; period < periods; period++) {
					xValues[(day * periods + period)] = tsBegin;
					yValues[(day * periods + period)] = period;
					zValues[(day * periods + period)] = 0.5;
				}
				cal.add(Calendar.DAY_OF_MONTH, 1);
				tsBegin = cal.getTimeInMillis();
			}

			localDefaultXYZDataset.addSeries("Series 1", new double[][]{xValues, yValues, zValues});
			saveToFile(new double[][]{xValues, yValues, zValues}, "D:\\_proyectoAlz\\analysis\\gps charts\\" + userID + "\\", beginDate + ".alz5");
			this.filename = beginDate;
		}
		return localDefaultXYZDataset;
	}

	private XYZDataset createDatasetFromCounts(ResultSet resultSet) {
		DefaultXYZDataset localDefaultXYZDataset = new DefaultXYZDataset();
		int periods = 1440;

		double axisX, axisY, axisZ;
		int magnitude;
		ArrayList<AccelerometerMeasure> accelerometerMeasures = new ArrayList<>();

		try {
			while (resultSet.next()) {
				axisX = resultSet.getDouble(1);
				axisY = resultSet.getDouble(2);
				axisZ = resultSet.getDouble(3);
				magnitude =
						(int) StrictMath.round(Math.sqrt(Math.pow(axisX, 2) + Math.pow(axisY, 2) + Math.pow(axisZ, 2)));
				accelerometerMeasures.add(new AccelerometerMeasure(
						axisX,
						axisY,
						axisZ,
						magnitude,
						resultSet.getLong(4)));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}


		double[] xValues, yValues, zValues, zCount;

		if (!accelerometerMeasures.isEmpty()) {
			long d1 = accelerometerMeasures.get(0).getTimestamp();
			long d2 = accelerometerMeasures.get(accelerometerMeasures.size() - 1).getTimestamp();
			int numberOfDays = TimeUtil.getDayDifference(d1, d2);
			int dataSize = periods * numberOfDays;

			xValues = new double[dataSize];
			yValues = new double[dataSize];
			zValues = new double[dataSize];
			zCount = new double[dataSize];

			Calendar cal = TimeUtil.getDayTimestamp(d1);
			long tsAux = cal.getTimeInMillis();
			long tsBegin = tsAux;

			for (int day = 0; day < numberOfDays; day++) {

				for (int period = 0; period < periods; period++) {

					System.out.println(day + " " + period);
					xValues[(day * periods + period)] = tsBegin;
					yValues[(day * periods + period)] = period;
					double[] valueCount = getValueCount(accelerometerMeasures, tsAux);
					zValues[(day * periods + period)] = valueCount[1];
					zCount[(day * periods + period)] = valueCount[0];

					tsAux += periodMs;
				}

				cal.add(Calendar.DAY_OF_MONTH, 1);
				tsBegin = tsAux = cal.getTimeInMillis();
			}

			this.filename = d1;
		} else {
			int numberOfDays = TimeUtil.getDayDifference(beginDate, endDate - 1);
			int dataSize = periods * numberOfDays;

			xValues = new double[dataSize];
			yValues = new double[dataSize];
			zValues = new double[dataSize];
			zCount = new double[dataSize];

			Calendar cal = TimeUtil.getDayTimestamp(beginDate);
			long tsAux = cal.getTimeInMillis();
			long tsBegin = tsAux;

			for (int day = 0; day < numberOfDays; day++) {
				for (int period = 0; period < periods; period++) {
					xValues[(day * periods + period)] = tsBegin;
					yValues[(day * periods + period)] = period;
					zValues[(day * periods + period)] = 0.5;
					zCount[(day * periods + period)] = -1;
				}
				cal.add(Calendar.DAY_OF_MONTH, 1);
				tsBegin = cal.getTimeInMillis();
			}

			this.filename = beginDate;
		}

		localDefaultXYZDataset.addSeries("Series 1", new double[][]{xValues, yValues, zValues});
		saveToFile(new double[][]{xValues, yValues, zValues}, "D:\\_proyectoAlz\\analysis\\accelerometer\\counts\\" + AccelerometerCount.getAlpha() + "\\" + userID + "\\", this.filename + ".alz5");
		saveToFile(new double[][]{xValues, yValues, zCount}, "D:\\_proyectoAlz\\analysis\\accelerometer\\counts\\" + AccelerometerCount.getAlpha() + "\\" + userID + "\\", this.filename + ".ct5");

		return localDefaultXYZDataset;
	}


	private XYZDataset createDatasetFromFiles(String path) {
		DefaultXYZDataset localDefaultXYZDataset = new DefaultXYZDataset();

		File dir = new File(path);
		FilenameFilter filter = new FilenameFilter() {
			public boolean accept(File dir, String name) {
				return name.toLowerCase().endsWith(".alz");
			}
		};
		File[] files = dir.listFiles(filter);

		if (files != null) {
			double[][] values = new double[3][1440 * files.length];
			int day = 0;

			for (File file : files) {
				try {
					double[][] valuesAux = loadData(file.getCanonicalPath());
					for (int i = 0; i < 1440; i++) {
						values[0][day * 1440 + i] = valuesAux[0][i];
						values[1][day * 1440 + i] = valuesAux[1][i];
						values[2][day * 1440 + i] = valuesAux[2][i];
					}
					day++;

				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			localDefaultXYZDataset.addSeries("Series 1", values);
		}

		return localDefaultXYZDataset;
	}

	private XYZDataset createDatasetFromCountFiles(String path) {
		DefaultXYZDataset localDefaultXYZDataset = new DefaultXYZDataset();

		File dir = new File(path);
		FilenameFilter filter = new FilenameFilter() {
			public boolean accept(File dir, String name) {
				return name.toLowerCase().endsWith(".ct");
			}
		};
		File[] files = dir.listFiles(filter);

		if (files != null) {
			double[][] values = new double[3][1440 * files.length];
			int day = 0;
			double intensity, intensityAux = -1;
			int intensityTypeAux = -1;
			int c = 0;
//			int epoch10ll = 0, epoch10hl = 0, epoch10lm = 0, epoch10hm = 0, epoch10h = 0;
			initiateEpochCount();
			Queue<Double> queue = new LinkedList<>();
			initiateQueue(queue);

			for (File file : files) {
				try {
					double[][] valuesAux = loadData(file.getCanonicalPath());
					for (int i = 0; i < 1440; i++) {
						values[0][day * 1440 + i] = valuesAux[0][i];
						values[1][day * 1440 + i] = valuesAux[1][i];
//						values[2][day * 1440 + i] = getIntensityDetailed(valuesAux[2][i]);
//						if (!isFromLast7Days(file)) {
//							intensity = 0.5;
//						}
//						else {
						intensity = getIntensity(valuesAux[2][i]);
						addToQueue(queue, intensity);
//						}
						values[2][day * 1440 + i] = intensity;

						if (intensityTypeAux != intensityType) {
							if (c >= 5 && intensityTypeAux != -1 && intensityTypeAux != 0 && intensityTypeAux != 1) {
								epoch10Count[intensityTypeAux - 2]++;
							}
							c = 1;
							intensityTypeAux = intensityType;
						} else {
							c++;
						}
					}
					day++;

				} catch (IOException e) {
					e.printStackTrace();
				}


			}


//			printEpochCount();
			printCount();

			localDefaultXYZDataset.addSeries("Series 1", values);
		}

		return localDefaultXYZDataset;
	}

	private XYZDataset createDatasetFromCountFilesB(String path) {
		DefaultXYZDataset localDefaultXYZDataset = new DefaultXYZDataset();

		File dir = new File(path);
		FilenameFilter filter = new FilenameFilter() {
			public boolean accept(File dir, String name) {
				return name.toLowerCase().endsWith(".ct");
			}
		};
		File[] files = dir.listFiles(filter);

		if (files != null) {
			double[][] values = new double[3][1440 * files.length];
			int day = 0;
			double intensity, intensityAux = -1;
			int intensityTypeAux = -1;
			int c = 0;
//			int epoch10ll = 0, epoch10hl = 0, epoch10lm = 0, epoch10hm = 0, epoch10h = 0;
			initiateEpochCount();
			Queue<Double> queue = new LinkedList<>();
			initiateQueue(queue);

			for (File file : files) {
				try {
					double[][] valuesAux = loadData(file.getCanonicalPath());
					for (int i = 0; i < 1440; i++) {
						values[0][day * 1440 + i] = valuesAux[0][i];
						values[1][day * 1440 + i] = valuesAux[1][i];
//						values[2][day * 1440 + i] = getIntensityDetailed(valuesAux[2][i]);
//						if (!isFromLast7Days(file)) {
//							intensity = 0.5;
//						}
//						else {
						intensity = getIntensity(valuesAux[2][i]);
						addToQueue(queue, intensity);
//						}
						values[2][day * 1440 + i] = intensity;

						if (intensityTypeAux != intensityType) {
							if (c >= 5 && intensityTypeAux != -1 && intensityTypeAux != 0 && intensityTypeAux != 1) {
								epoch10Count[intensityTypeAux - 2]++;
							}
							c = 1;
							intensityTypeAux = intensityType;
						} else {
							c++;
						}
					}
					day++;

				} catch (IOException e) {
					e.printStackTrace();
				}


			}


//			printEpochCount();
			printCount();

			localDefaultXYZDataset.addSeries("Series 1", values);
		}

		return localDefaultXYZDataset;
	}

	private boolean isFromLast7Days(File file) {
		if (Long.valueOf(file.getName().substring(0, 13)) >= lastDays[userID - 1]) {
			return true;
		}

		return false;
	}

	private double getValue(ArrayList<AccelerometerMeasure> magnitudes, long tsAux) {
		long tsA = tsAux;
		long tsB = tsAux + periodMs;

		double value = 0.5;
		double valueAux;
		long mTimestamp;
		boolean moved = false;

		while (!magnitudes.isEmpty()) {

			mTimestamp = magnitudes.get(0).getTimestamp();

			if (mTimestamp > tsB) {
//				magnitudes.remove(0);
				break;
			}

			if (mTimestamp > tsA && mTimestamp <= tsB) {
//				System.out.println("in");
				if (moved(magnitudes.get(0).getMagnitude())) {
					value = 2.5;
					moved = true;
				} else if (!moved) {
//					System.out.println("no movement");
					value = 1.5;
				}
			}

			magnitudes.remove(0);
		}

		return value;
	}

	private double[] getValueCount(ArrayList<AccelerometerMeasure> accMeasures, long tsAux) {
		long tsA = AccelerometerUtil.timestampAux = tsAux;
		long tsB = tsAux + periodMs;

		double value = 0.5;
		double count = -1;
		long mTimestamp;

		int accFilteredMagnitudesRounded = 0;
		double[] accFM;

		int freqForAvg = 0, counter = 0;
		long frequency, invalidFrequency = 0;

		if (!accMeasures.isEmpty()) {
			while (!accMeasures.isEmpty()) {
				mTimestamp = accMeasures.get(0).getTimestamp();

				if (mTimestamp > tsB) {
					break;
				}

				if (mTimestamp > tsA && mTimestamp <= tsB) {
					frequency = mTimestamp - AccelerometerUtil.timestampAux;
					if (frequency > AccelerometerUtil.maxFrequency) {
						invalidFrequency += -AccelerometerUtil.expectedFrequency + frequency;
					} else {
						freqForAvg += frequency;
						counter++;
					}

					accFM = AccelerometerCount.getFilteredAcceleration(
							accMeasures.get(0).getAxisX(), accMeasures.get(0).getAxisY(), accMeasures.get(0).getAxisZ());
					accFilteredMagnitudesRounded += StrictMath.round(Math.sqrt(
							Math.pow(accFM[0], 2) +
									Math.pow(accFM[1], 2) +
									Math.pow(accFM[2], 2)));

					AccelerometerUtil.timestampAux = mTimestamp;
				}

				accMeasures.remove(0);
			}

			if (counter != 0) {
				float freqAvg = (float) freqForAvg / counter;
				float freqRatio = (float) AccelerometerUtil.expectedFrequency / freqAvg;
				long time = 60000 - invalidFrequency;

				count = ((float) accFilteredMagnitudesRounded / (((float) time / 1000) / 60)) / freqRatio;
				value = getIntensity(count);
			}
		}

		return new double[]{count, value};
	}

	private double getIntensity(double count) {
		if (count == -1) {
			//no data
			intensityType = 0;
			return 0.5;
		}
		if (count <= 50) {
			//sedentary
			intensityType = 1;
			return 1.5;
		}
		if (count <= 100) {
			//sedentary
			intensityType = 1;
			return 2.5;
		}
		if (count <= 1952) {
			//light
			intensityType = 2;
			return 3.5;
		}
		if (count <= 5724) {
			//moderate
			intensityType = 3;
			return 4.5;
		}
		//hard
		intensityType = 4;
		return 5.5;
	}

	private double getIntensityDetailed(double count) {
		if (count == -1) {
			//no data
			intensityType = 0;
			return 0.5;
		}
		if (count <= 40) {
			//sedentary
			intensityType = 0;
			return 1.5;
		}
		if (count <= 100) {
			//sedentary
			intensityType = 1;
			return 1.5;
		} else if (count <= 929) {
			//low light
			intensityType = 2;
			return 2.5;
		} else if (count <= 1952) {
			//high light
			intensityType = 3;
			return 3.5;
		} else if (count <= 3299) {
			//low moderate
			intensityType = 4;
			return 4.5;
		} else if (count <= 5724) {
			//high moderate
			intensityType = 5;
			return 5.5;
		} else {
			//hard
			intensityType = 6;
			return 6.5;
		}
	}

	private void initiateEpochCount() {
		for (int i = 0; i <= 4; i++) {
			epoch10Count[i] = 0;
		}
	}

	private void initiateQueue(Queue<Double> queue) {
//		queue = new LinkedList<>();
		queue.clear();
		for (int i = 1; i <= 10; i++) {
			queue.add(0.5);
		}
		lightIntensity = 0;
		moderateIntensity = 0;
		hardIntensity = 0;
	}

	private void addToQueue(Queue<Double> queue, double intensity) {
		queueModified(queue.poll(), -1);
		queue.add(intensity);
		queueModified(intensity, 1);
		checkValues(queue);
	}

	private void queueModified(double value, int aux) {
		if (value == 3.5) {
			lightIntensity += aux;
			return;
		}
		if (value == 4.5) {
			moderateIntensity += aux;
			return;
		}
		if (value == 5.5) {
			hardIntensity += aux;
		}
	}

	private void checkValues(Queue<Double> queue) {
		boolean initiate = false;
		if (lightIntensity >= 8) {
			cLight++;
			initiate = true;
		} else if (moderateIntensity >= 8) {
			cModerate++;
			initiate = true;
		} else if (hardIntensity >= 8) {
			cHard++;
			initiate = true;
		}
		if (initiate) {
			initiateQueue(queue);
		}
	}

	private void printCount() {
//		System.out.println("-----USER " + userID + "-----");
		System.out.println(cLight + " " + cModerate + " " + cHard);
//		System.out.println(cModerate);
//		System.out.println(cHard);
	}


	private void printEpochCount() {
		System.out.println("-----USER " + userID + "-----");
		for (int i = 0; i <= 4; i++) {
			System.out.println(epoch10Count[i]);
		}
//		System.out.println("----------------");
	}


	private JFreeChart createChart(XYZDataset xyzDataset) {
		DateAxis localDateAxis = new DateAxis("Date");
		localDateAxis.setLowerMargin(0.0D);
		localDateAxis.setUpperMargin(0.0D);
		localDateAxis.setInverted(true);

		NumberAxis localNumberAxis = new NumberAxis("Hour");
		localNumberAxis.setUpperMargin(0.0D);
		localNumberAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

		XYBlockRenderer localXYBlockRenderer = new XYBlockRenderer();
		localXYBlockRenderer.setBlockWidth(86400000.0D);
		localXYBlockRenderer.setBlockAnchor(RectangleAnchor.BOTTOM_LEFT);
		LookupPaintScale localLookupPaintScale = new LookupPaintScale(0.5, 3.5, Color.RED);
		localLookupPaintScale.add(0.5, Color.RED);
		localLookupPaintScale.add(1.5, Color.BLUE);
		localLookupPaintScale.add(2.5, Color.GREEN);
//    localLookupPaintScale.add(3.5D, Color.YELLOW);
		localXYBlockRenderer.setPaintScale(localLookupPaintScale);

		XYPlot localXYPlot = new XYPlot(xyzDataset, localDateAxis, localNumberAxis, localXYBlockRenderer);
		localXYPlot.setOrientation(PlotOrientation.HORIZONTAL);
		localXYPlot.setBackgroundPaint(Color.WHITE);
		localXYPlot.setRangeGridlinePaint(Color.WHITE);
		localXYPlot.setAxisOffset(new RectangleInsets(5.0D, 5.0D, 5.0D, 5.0D));

		JFreeChart localJFreeChart = new JFreeChart("Accelerometer Chart: " + userID, localXYPlot);
		localJFreeChart.removeLegend();
		localJFreeChart.setBackgroundPaint(Color.WHITE);

		SymbolAxis localSymbolAxis = new SymbolAxis(null, new String[]{"", "No Data", "No Movement", "Movement", "Group 2"});
		localSymbolAxis.setRange(0.5D, 4.5D);
		localSymbolAxis.setPlot(new PiePlot());
		localSymbolAxis.setGridBandsVisible(false);
		PaintScaleLegend localPaintScaleLegend = new PaintScaleLegend(localLookupPaintScale, localSymbolAxis);
		localPaintScaleLegend.setMargin(new RectangleInsets(3.0D, 10.0D, 3.0D, 10.0D));
		localPaintScaleLegend.setPosition(RectangleEdge.BOTTOM);
		localPaintScaleLegend.setAxisOffset(5.0D);
		localJFreeChart.addSubtitle(localPaintScaleLegend);
		ChartUtilities.applyCurrentTheme(localJFreeChart);
		return localJFreeChart;
	}

	private JFreeChart createIntensityChart(XYZDataset xyzDataset) {
		DateAxis localDateAxis = new DateAxis("Date");
		localDateAxis.setLowerMargin(0.0D);
		localDateAxis.setUpperMargin(0.0D);
		localDateAxis.setInverted(true);

		NumberAxis localNumberAxis = new NumberAxis("Hour");
		localNumberAxis.setUpperMargin(0.0D);
		localNumberAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

		XYBlockRenderer localXYBlockRenderer = new XYBlockRenderer();
		localXYBlockRenderer.setBlockWidth(86400000.0D);
		localXYBlockRenderer.setBlockAnchor(RectangleAnchor.BOTTOM_LEFT);


		XYPlot localXYPlot = new XYPlot(xyzDataset, localDateAxis, localNumberAxis, localXYBlockRenderer);
		localXYPlot.setOrientation(PlotOrientation.HORIZONTAL);
		localXYPlot.setBackgroundPaint(Color.WHITE);
		localXYPlot.setRangeGridlinePaint(Color.WHITE);
		localXYPlot.setAxisOffset(new RectangleInsets(5.0D, 5.0D, 5.0D, 5.0D));

		JFreeChart localJFreeChart = new JFreeChart("Activity Intensity Chart: " + userID, localXYPlot);
		localJFreeChart.removeLegend();
		localJFreeChart.setBackgroundPaint(Color.WHITE);

		/*SymbolAxis localSymbolAxis = new SymbolAxis(null, new String[]{"", "No Data", "Sedentary", "Low Light", "High Light", "Low Moderate", "High Moderate", "Hard"});
		localSymbolAxis.setRange(0.5D, 6.5D);*/
		LookupPaintScale localLookupPaintScale = new LookupPaintScale(0.5, 6.5, Color.RED);
		localLookupPaintScale.add(0.5, Color.LIGHT_GRAY);
		localLookupPaintScale.add(1.5, new Color(151, 205, 255));
		localLookupPaintScale.add(2.5, Color.WHITE);
		localLookupPaintScale.add(3.5, new Color(220, 243, 148));
		localLookupPaintScale.add(4.5, new Color(38, 173, 31));
		localLookupPaintScale.add(5.5, new Color(255, 107, 36));
		localXYBlockRenderer.setPaintScale(localLookupPaintScale);

		SymbolAxis localSymbolAxis = new SymbolAxis(null, new String[]{"", "No Data", "No Movement", "Sedentary", "Light", "Moderate", "Hard"});
		localSymbolAxis.setRange(0.5D, 6.5D);
		localSymbolAxis.setPlot(new PiePlot());
		localSymbolAxis.setGridBandsVisible(false);

		PaintScaleLegend localPaintScaleLegend = new PaintScaleLegend(localLookupPaintScale, localSymbolAxis);
		localPaintScaleLegend.setMargin(new RectangleInsets(3.0D, 10.0D, 3.0D, 10.0D));
		localPaintScaleLegend.setPosition(RectangleEdge.BOTTOM);
		localPaintScaleLegend.setAxisOffset(5.0D);

		localJFreeChart.addSubtitle(localPaintScaleLegend);

		ChartUtilities.applyCurrentTheme(localJFreeChart);

		return localJFreeChart;
	}


	public boolean moved(double magnitude) {
		return !(magnitude > dataType1Min && magnitude < dataType1Max);
	}

	public static void saveToFile(Object object, String folder, String filename) {
		try {
			File file = new File(folder);
			file.mkdirs();
			ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(new File(folder + filename)));
			stream.writeObject(object);
			stream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static double[][] loadData(String filename) {
		File file = new File(filename);
		if (file.exists()) {
			try {
				ObjectInputStream str = new ObjectInputStream(new FileInputStream(file));
				return (double[][]) str.readObject();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	public static void joinFiles(String folder, String filename, String filename1, String filename2) {
		double[][] data1 = loadData(folder + filename1);
		double[][] data2 = loadData(folder + filename2);
		double[][] data = new double[3][1440];

		if (data1 != null && data2 != null) {
			for (int i = 0; i < 720; i++) {
				data[0][i] = data1[0][i];
				data[1][i] = data1[1][i];
				data[2][i] = data1[2][i];
			}
			for (int i = 720; i < 1440; i++) {
				data[0][i] = data2[0][i];
				data[1][i] = data2[1][i];
				data[2][i] = data2[2][i];
			}

			saveToFile(data, folder, filename);
		}
	}

//	public static void joinFiles(String folder, String filename) {
//		double[][] data1 = loadData(folder + filename1);
//		double[][] data2 = loadData(folder + filename2);
//		double[][] data = new double[3][1440];
//
//		if (data1 != null && data2 != null) {
//			for (int i = 0; i < 720; i++) {
//				data[0][i] = data1[0][i];
//				data[1][i] = data1[1][i];
//				data[2][i] = data1[2][i];
//			}
//			for (int i = 720; i < 1440; i++) {
//				data[0][i] = data2[0][i];
//				data[1][i] = data2[1][i];
//				data[2][i] = data2[2][i];
//			}
//
//			saveToFile(data, folder, filename);
//		}
//	}
}